#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#define SIZE 256
#define LENTH 128
void Split(char* command,char* argv[])
{
int index = 0;
  argv[index] = strtok(command," ");
  while(argv[index] != NULL)
  {
    index++;
    argv[index] = strtok(NULL," ");
  }
}
void Debug(char* argv[])
{
  printf("argv:");
  for(int i = 0; argv[i];i++)
  {
    printf("argv[%d]:%s ",i,argv[i]);
  }

}
void showenv()
{
  extern char** environ;
  for(int i = 0;environ[i];i++)
  {
    printf("%d：%s\n",i,environ[i]);    
  }
}
int main()
{
  extern char** environ; //导入系统环境变量
  char myenv[36][256] = {NULL};  //保存环境变量
  int EnvIndex = 0;
  int last_status; //存储退出码
  while(1)
  {
  char command[LENTH] = {0}; //存储字符串指令
  char* argv[SIZE] ={NULL};
  printf("[pcj@izbp1e4cmvtbfywbc12345 myshell]$"); //和shell一样的图形化提示
  fflush(stdout);  //添加fflush刷新缓冲区
   // sleep(1);
  fgets(command,sizeof(command),stdin);  //获取指令
  //将指令后面的\n去掉 acc\n\0,如果不去掉\n,子进程将无法正常调用execvp函数
  command[strlen(command)-1] = '\0';
  Split(command,argv); //将指令进行切割，获取指令名称
   //测试分割指令是否正确
  // Debug(argv);
  
  //更改细节
   if(strcmp(argv[0],"ls")==0)
   {//使ls指令使用时带上颜色
     int i = 0;
     for(;argv[i];i++);
      argv[i++] =(char*) "--color=auto";
      argv[i] = NULL; //增加代码健壮性
   
    }else if(strcmp(argv[0],"cd")==0)
    {
      if(argv[1] != NULL) chdir(argv[1]);
      continue; //为什么加continue,增加代码健壮性，不需要执行后续代码
    }else if(strcmp(argv[0],"export") == 0)//其实我们之前学的环境变量命令都是内建命令
    {
      strcpy(myenv[EnvIndex],argv[1]);
      putenv(myenv[EnvIndex++]);
      continue;
    }else if(strcmp(argv[0],"env")==0) //如果不写这个逻辑，env查的不是父进程的环境变量，而是子进程的环境变量
    {
       showenv();
       continue;
    }else if(strcmp(argv[0],"echo")==0)
    {
          //echo $PATH
          const char* target_env = NULL;
           if(argv[1][0] == '$')
           {
             if(argv[1][1] == '?')
             {
               printf("%d\n",last_status);
               continue;
             }else 
             {
               target_env = getenv(argv[1]+1); //传环境变量的地址
              printf("%s=%s\n",argv[1]+1,target_env);
             }
           }
           continue;
    }

  //指令分割完成，创建子进程调用程序
  pid_t id = fork();  //创建子进程
  if(id == 0)
  {//子进程
    //更改细节  --->在这里更改细节在进程里面更改和父进程里面更改有什么区别？没有区别，因为程序替换的代码在后面，而不是在这段代码的前面--》为了代码好看，我们在父进程进行修改
//  if(strcmp(argv[0], "ls")==0)
//    {//如果是ls要进行什么操作
//      int i = 1;
//       for(;argv[i];i++);
//       argv[i++] =(char*) "--color=auto";
//       argv[i] = NULL;
//    }else if(strcmp(argv[0],"cd")==0)
//    {
//      chdir(argv[1]);
//      continue; //为什么加continue,增加代码健壮性，不需要执行后续代码
//    }
  //     //else if(argv[0] == "cd")
   // {//如果是cd要进行什么操作

   // }else if(argv[0] == "echo")
   // {

   // }
   // if(strcmp(argv[0],"export")==0)
  // {
     // if(argv[1] != NULL) putenv(argv[1]); //不能直接压入argv[1];因为环境变量存储在链表数组里面，链表指向的变量是不断变化的，所以env看不到环境变量的值
   //    execvpe(argv[0],argv,environ);
  //     continue;
 // }
 // execvp(argv[0],argv);
  execvpe(argv[0],argv,environ);
    exit(0);
  }
  int status = 0;
   pid_t ret = waitpid(id,&status,0);
   if(ret > 0)
   {
     last_status = WIFEXITED(status);
   }
  }
 // printf("指令是%s\n",command); //测试--查看指令
  return 0;
}
